package etxt2db.annotators;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import edu.cmu.minorthird.text.Annotator;
import edu.cmu.minorthird.text.MonotonicTextLabels;
import edu.cmu.minorthird.text.Span;
import edu.cmu.minorthird.text.TextLabels;
import etxt2db.api.ClassificationModel;
import etxt2db.minorthird.MultiClassAnnotatorLearner;
import etxt2db.minorthird.MultiClassSequenceAnnotatorLearner;
import etxt2db.minorthird.MultiClassTextLabelsAnnotatorTeacher;
import etxt2db.minorthird.MultiClassSequenceAnnotatorLearner.MultiClassSequenceAnnotator;
import etxt2db.utils.MegaCartesianProduct;


public abstract class MinorthirdClassificationModel extends ClassificationModel implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 2399229676481289929L;

	protected Set<Set<String>> compatibleAttributes = new HashSet<Set<String>>();
	
	protected transient List<MultiClassAnnotatorLearner> learners = new ArrayList<MultiClassAnnotatorLearner>();
	protected Annotator ann;
	
	protected Annotator doTraining (TextLabels labels) throws IOException{
		OverlapedTagClassificationModel result = new OverlapedTagClassificationModel();
		int i = 0;
		for(Set<String> setStr : compatibleAttributes){
			List<String> listStr = new ArrayList<String>(setStr);
			MultiClassAnnotatorLearner learner = learners.get(i);
			// Load the Learner according to the technique we want to use
			learner.setAnnotationType(listStr);
		
			// Create the teacher to develop an Annotator to the given attribute
			MultiClassTextLabelsAnnotatorTeacher teacher = new MultiClassTextLabelsAnnotatorTeacher(labels,listStr);

			// Train the Annotator
			result.addAnnotator(teacher.train(learner));
			i++;
		}
		return result;
	}
	
	public void annotate(MonotonicTextLabels arg0) {
		ann.annotate(arg0);	
	}

	public TextLabels annotatedCopy(TextLabels arg0) {
		return ann.annotatedCopy(arg0);
	}

	public String explainAnnotation(TextLabels arg0, Span arg1) {
		return null;
	}
	
	@Override
	public List<Annotator> getAlternativeImplementations(){
		List<Annotator> result = new ArrayList<Annotator>();
		result.addAll(getAlternativeImplementationModel());
		return result;
	}
	
	public List<ClassificationModel> getAlternativeImplementationModel(){
		OverlapedTagClassificationModel ann = (OverlapedTagClassificationModel) this.ann;
		
		Map<MultiClassSequenceAnnotator,List<Integer>> input = new HashMap<MultiClassSequenceAnnotator,List<Integer>>();
		for(Annotator a : ann.annotators){
			MultiClassSequenceAnnotator myAnnot = (MultiClassSequenceAnnotator) a;
			List<Integer> newList = new ArrayList<Integer>();
			for(int i=1; i<myAnnot.getMaximumBeamSize();i++){
				newList.add(i);
			}
			input.put(myAnnot, newList);
		}
		List<Map<MultiClassSequenceAnnotator,Integer>> out = MegaCartesianProduct.generateAllPossibilities(input);
		
		List<ClassificationModel> result = new ArrayList<ClassificationModel>();
		
		for(Map<MultiClassSequenceAnnotator,Integer> r : out){
			OverlapedTagClassificationModel actualResult = new OverlapedTagClassificationModel();
			for(Entry<MultiClassSequenceAnnotator,Integer> entry : r.entrySet()){
				MultiClassSequenceAnnotator annot = entry.getKey().copy();
				annot.setBeamSize(entry.getValue());
				actualResult.addAnnotator(annot);
				annot.setAlternateModelInfo("k=" + entry.getValue());
			}
			result.add(actualResult);
		}
		return result;
	}
}
